
/*
 * Copyright (c) 2020-2021, SERI Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-06-23     Lyons        first version
 */

/**
  * @brief Define Shell Command Buffer Max Length, Byte
  */

#ifndef SHELL_CMD_SIZE
#define SHELL_CMD_SIZE (128)
#endif

/**
  * @brief Define Shell Controller Structure
  */

struct xshell
{
    char line[SHELL_CMD_SIZE];

    enum
    {
        WAIT_NORMAL,
        WAIT_SPEC_KEY,
        WAIT_FUNC_KEY,
    } stat;

    uint16_t line_position;
    uint16_t line_curpos;
};

static int shell_getline(struct xcli *cli, char ch)
{
    static struct xshell shell = {0};

    if (ch < 0) {
        return 0;
    }

    do {
        /* handle control key */
        if (ch == 0x1b)
        {
            shell.stat = WAIT_SPEC_KEY;
            break;
        }
        else if (shell.stat == WAIT_SPEC_KEY)
        {
            if (ch == 0x5b)
            {
                shell.stat = WAIT_FUNC_KEY;
                break;
            } else { 
                shell.stat = WAIT_NORMAL;
            }
        }
        else if (shell.stat == WAIT_FUNC_KEY)
        {
            shell.stat = WAIT_NORMAL;

            /* up key */
            if (ch == 0x41)
            {
                break;
            }
            /* down key */
            else if (ch == 0x42)
            {
                break;
            }
            /* right key */
            else if (ch == 0x43)
            {
                if (shell.line_curpos < shell.line_position)
                {
                    printf("%c", shell.line[shell.line_curpos]);
                    shell.line_curpos ++;
                }
                break;
            }
            /* left key */
            else if (ch == 0x44)
            {
                if (shell.line_curpos)
                {
                    printf("\b");
                    shell.line_curpos --;
                }
                break;
            }
        }

        /* handle tab key */
        if (ch == '\t')
        {
            break;
        }
        /* handle backspace key */
        else if (ch == 0x08 || ch == 0x7f)
        {
            if (shell.line_curpos == 0) {
                break;
            }

            shell.line_position--;
            shell.line_curpos--;

            if (shell.line_curpos < shell.line_position)
            {
                memmove(&shell.line[shell.line_curpos],
                        &shell.line[shell.line_curpos + 1],
                        shell.line_position - shell.line_curpos);
                shell.line[shell.line_position] = 0;

                printf("\b%s ", &shell.line[shell.line_curpos]);

                /* move the cursor to the origin position */
                for (int i = shell.line_curpos; i <= shell.line_position; i++) {
                    printf("\b");
                }
            }
            else
            {
                printf("\b \b");
                shell.line[shell.line_position] = 0;
            }

            break;
        }
        /* handle enter key */
        else if (ch == '\r' || ch == '\n')
        {
            strcpy(cli->cmd.command, shell.line);
            cli->cmd.submit = 1;

            CLEAR_STRUCT(shell, 0);
            break;
        }

        /* normal character */
        if (shell.line_curpos < shell.line_position)
        {
            memmove(&shell.line[shell.line_curpos + 1],
                    &shell.line[shell.line_curpos],
                    shell.line_position - shell.line_curpos);
            shell.line[shell.line_curpos] = ch;
            printf("%s", &shell.line[shell.line_curpos]);

            /* move the cursor to new position */
            for (int i = shell.line_curpos; i < shell.line_position; i++) {
                printf("\b");
            }
        }
        else
        {
            shell.line[shell.line_position] = ch;
            printf("%c", ch);
        }

        shell.line_position ++;
        shell.line_curpos ++;
        if (shell.line_position >= SHELL_CMD_SIZE)
        {
            shell.line_position = 0;
            shell.line_curpos = 0;
        }
    } while (0);

    return 0;
}
